﻿using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using pandx.Mulan.Flow.FlowSchemes.Dto;
using pandx.Mulan.Flows;
using Abp.Linq.Extensions;
using System.Linq;
using Abp.Authorization;
using Abp.Extensions;
using Microsoft.EntityFrameworkCore;
using pandx.Mulan.Authorization;
using pandx.Mulan.Authorization.Users;
using pandx.Mulan.Dto;
using pandx.Mulan.Flow.FlowSchemes.Exporting;

namespace pandx.Mulan.Flow.FlowSchemes
{
    public class FlowSchemeAppService:MulanAppServiceBase,IFlowSchemeAppService
    {
        private readonly IRepository<FlowScheme, long> _flowSchemeRepository;
        private readonly IRepository<User, long> _userRepository;
        private readonly IFlowSchemeListExcelExporter _flowSchemeListExcelExporter;

        public FlowSchemeAppService(
            IRepository<FlowScheme, long> flowSchemeRepository,
            IRepository<User,long> userRepository,
            IFlowSchemeListExcelExporter flowSchemeListExcelExporter
            )
        {
            _userRepository = userRepository;
            _flowSchemeRepository = flowSchemeRepository;
            _flowSchemeListExcelExporter = flowSchemeListExcelExporter;
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_FlowSchemes_Browse)]
        public async Task<PagedResultDto<FlowSchemeListDto>> ObtainFlowSchemes(ObtainFlowSchemesInput input)
        {

            var query = CreateFlowSchemeAndUsersQuery(input);
            
            var schemesCount = await query.CountAsync();
            var schemes = await query.OrderBy(input.Sorting).PageBy(input).ToListAsync();
            var dtos = schemes.Select(item =>
            {
                var dto = ObjectMapper.Map<FlowSchemeListDto>(item.FlowScheme);
                dto.CreatorUserName = item.User.UserName;
                dto.CreatorName = item.User.Name;
                return dto;
            }).ToList();
            return new PagedResultDto<FlowSchemeListDto>(schemesCount, dtos);
        }
        [AbpAuthorize(AppPermissions.Pages_Administration_FlowSchemes_Export)]
        public async Task<FileDto> ObtainFlowSchemesToExcel(ObtainFlowSchemesInput input)
        {
            var flowSchemes = await CreateFlowSchemeAndUsersQuery(input).AsNoTracking().OrderBy(input.Sorting).ToListAsync();
            var dtos=flowSchemes.Select(item =>
            {
                var dto = ObjectMapper.Map<FlowSchemeListDto>(item.FlowScheme);
                dto.CreatorUserName = item.User.UserName;
                dto.CreatorName = item.User.Name;
                return dto;
            }).ToList();
            return _flowSchemeListExcelExporter.ExportToExcel(dtos);
        }

        public async Task CreateOrUpdateFlowScheme(CreateOrUpdateFlowSchemeInput input)
        {
            if (input.FlowScheme.Id.HasValue)
            {
                await UpdateFlowSchemeAsync(input);
            }
            else
            {
                await CreateFlowSchemeAsync(input);
            }
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_FlowSchemes_Update)]
        protected virtual async Task UpdateFlowSchemeAsync(CreateOrUpdateFlowSchemeInput input)
        {
            var flowScheme = await _flowSchemeRepository.GetAsync(input.FlowScheme.Id.Value);
            ObjectMapper.Map(input.FlowScheme, flowScheme);
            await CurrentUnitOfWork.SaveChangesAsync();
        }
        [AbpAuthorize(AppPermissions.Pages_Administration_FlowSchemes_Create)]
        protected virtual async Task CreateFlowSchemeAsync(CreateOrUpdateFlowSchemeInput input)
        {
            if (AbpSession.TenantId.HasValue)
            {
            }

            var flowScheme = ObjectMapper.Map<FlowScheme>(input.FlowScheme);
            
            flowScheme.TenantId = AbpSession.TenantId;
            
            await _flowSchemeRepository.InsertAsync(flowScheme);
            await CurrentUnitOfWork.SaveChangesAsync();
        }
        [AbpAuthorize(AppPermissions.Pages_Administration_FlowSchemes_Create,AppPermissions.Pages_Administration_FlowSchemes_Update)]
        public async Task<GetFlowSchemeForEditOutput> GetFlowSchemeForEdit(NullableIdDto<long> input)
        {
            var output = new GetFlowSchemeForEditOutput();
            if (input.Id.HasValue)
            {
                var flowScheme = await _flowSchemeRepository.GetAsync(input.Id.Value);
                output.FlowScheme = ObjectMapper.Map<FlowSchemeEditDto>(flowScheme);
            }
            else
            {
                var flowScheme = new FlowSchemeEditDto();
                output.FlowScheme = flowScheme;
            }

            return output;
        }
        [AbpAuthorize(AppPermissions.Pages_Administration_FlowSchemes_Browse)]
        public async Task<FlowSchemeListDto> GetFlowScheme(EntityDto<long> input)
        {
            var scheme = await _flowSchemeRepository.GetAsync(input.Id);
            return ObjectMapper.Map<FlowSchemeListDto>(scheme);
        }
        [AbpAuthorize(AppPermissions.Pages_Administration_FlowSchemes_Delete)]
        public async Task DeleteFlowScheme(EntityDto<long> input)
        {
            var flowScheme = await _flowSchemeRepository.GetAsync(input.Id);
            await _flowSchemeRepository.DeleteAsync(input.Id);
        }
        
        private IQueryable<FlowSchemeAndUser> CreateFlowSchemeAndUsersQuery(ObtainFlowSchemesInput input)
        {
            var query = from flowScheme in _flowSchemeRepository.GetAll()
                join user in _userRepository.GetAll() on flowScheme.CreatorUserId equals user.Id into userJoin
                from joinedUser in userJoin.DefaultIfEmpty()
                where flowScheme.CreationTime >= input.StartTime && flowScheme.CreationTime <= input.EndTime
                select new FlowSchemeAndUser
                {
                    FlowScheme = flowScheme,
                    User=joinedUser
                };
            query = query
                .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.FlowScheme.SchemeName.Contains(input.Filter) || x.FlowScheme.Description.Contains(input.Filter));
            return query;
        }
        [AbpAuthorize(AppPermissions.Pages_Administration_FlowSchemes_Create,AppPermissions.Pages_Administration_FlowSchemes_Update)]
        public async Task<ValidateOutput> ValidateFlowSchemeName(ValidateInput<string, int> input)
        {
            if (input.Id == 0)
            {
                var one = await _flowSchemeRepository.GetAll().SingleOrDefaultAsync(r => r.SchemeName == input.Value);
                if (one != null)
                {
                    return new ValidateOutput
                    {
                        Status = false,
                        Message = "流程模板名 " + input.Value + " 已被占用"
                    };
                }
                else
                {
                    return new ValidateOutput
                    {
                        Status = true,
                    };
                }
            }
            else
            {
                var one = await _flowSchemeRepository.GetAll().SingleOrDefaultAsync(r =>
                    r.SchemeName == input.Value && r.Id != input.Id);
                if (one != null)
                {
                    return new ValidateOutput
                    {
                        Status = false,
                        Message = "流程模板名 " + input.Value + " 已被占用"
                    };
                }
                else
                {
                    return new ValidateOutput
                    {
                        Status = true,
                    };
                }
            }
        }
    }
}
